//----------------------------------------------------------------------------
// Anti-Grain Geometry - Version 2.4
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
//
// C# Port port by: Lars Brubaker
//                  larsbrubaker@gmail.com
// Copyright (C) 2007
//
// Permission to copy, use, modify, sell and distribute this software 
// is granted provided this copyright notice appears in all copies. 
// This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
//----------------------------------------------------------------------------
// Contact: mcseem@antigrain.com
//          mcseemagg@yahoo.com
//          http://www.antigrain.com
//----------------------------------------------------------------------------
//
// class platform_support
//
//----------------------------------------------------------------------------
using System;
using System.Diagnostics;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;

using AGG3D.Graphics;
using AGG.Image;
using AGG.RasterizerScanline;

namespace AGG.UI
{
    public class WindowsFormsBitmapBackendGuiFactory : IGuiFactory
    {
        public string GetFactoryName()
        {
            return "WindowsFormsBitmapBackendGuiFactory";
        }

        public GuiHalSurface CreateSurface(int Width, int Height, GuiHalSurface.CreateFlags flags, GuiHalSurface.PixelFormat pixelFormat)
        {
            GuiHalSurface newSurface;

            switch (pixelFormat)
            {
                case GuiHalSurface.PixelFormat.PixelFormatBgr24:
                    newSurface = new GuiHalSurfaceWindowsFormsBitmapBackend(GuiHalSurface.ImageFormats.pix_format_bgr24);
                    break;

                case GuiHalSurface.PixelFormat.PixelFormatBgra32:
                    newSurface = new GuiHalSurfaceWindowsFormsBitmapBackend(GuiHalSurface.ImageFormats.pix_format_bgra32);
                    break;

                case GuiHalSurface.PixelFormat.PixelFormatRgbaFloat:
                    newSurface = new GuiHalSurfaceWindowsFormsBitmapBackend(GuiHalSurface.ImageFormats.pix_format_rgba_float);
                    break;

                default:
                    throw new NotImplementedException();
            }

            newSurface.Init(Width, Height, flags, pixelFormat);
            return newSurface;
        }
    }

    public class WindowsFormBridgeBitmapBackend : AbstractWindowsFormBridge
    {
        public WindowsFormBridgeBitmapBackend(GuiHalSurface app, GuiHalSurface.ImageFormats format)
            : base(app, format)
        {
            SetUpFormsWindow(app, format);
        }

        public override void display_pmap(Graphics displayGraphics)
        {
            GuiHalSurfaceWindowsFormsBitmapBackend app = ((GuiHalSurfaceWindowsFormsBitmapBackend)m_app);
            app.m_BackBuffer.UpdateHardwareSurface();
            displayGraphics.DrawImage(app.m_BackBuffer.m_WidowsBitmap, 0, 0);
        }
    };

    public class GuiHalSurfaceWindowsFormsBitmapBackend : GuiHalSurfaceWindowsFormsBase
    {
        internal Win32BackBuffer m_BackBuffer = new Win32BackBuffer();

        public GuiHalSurfaceWindowsFormsBitmapBackend(ImageFormats format)
            : base(format)
        {
            windowsFormsWindow = new WindowsFormBridgeBitmapBackend(this, format);
        }

        public override void OnResize(int sx, int sy)
        {
            Bounds = new rect_d(0, 0, sx, sy); ;
            int bitDepth = GuiHalSurface.GetBitDepthForPixelFormat(m_format);
            m_BackBuffer.Initialize((int)Width, (int)Height, bitDepth);
            NewGraphics2D().Clear(new RGBA_Doubles(1, 1, 1, 1));
        }

        public override Graphics2D NewGraphics2D()
        {
            Graphics2D graphics2D;
            if (m_BackBuffer.m_BackBufferImage != null)
            {
                graphics2D = m_BackBuffer.m_BackBufferImage.NewGraphics2D();
            }
            else
            {
                graphics2D = m_BackBuffer.m_BackBufferImageFloat.NewGraphics2D();
            }
            graphics2D.PushTransform();
            return graphics2D;
        }

        public override void Init(int Width, int Height, GuiHalSurface.CreateFlags flags, GuiHalSurface.PixelFormat pixelFormat)
        {
            if (windowsFormsWindow.m_sys_format == GuiHalSurface.ImageFormats.pix_format_undefined)
            {
                throw new InvalidDataException();
            }

            m_window_flags = flags;

            System.Drawing.Size clientSize = new System.Drawing.Size();
            clientSize.Width = Width;
            clientSize.Height = Height;
            windowsFormsWindow.ClientSize = clientSize;

            if ((m_window_flags & CreateFlags.Resizable) == 0)
            {
                windowsFormsWindow.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
                windowsFormsWindow.MaximizeBox = false;
            }

            initialWidth = Width;
            initialHeight = Height;

            clientSize.Width = Width;
            clientSize.Height = Height;
            windowsFormsWindow.ClientSize = clientSize;

            Bounds = new rect_d(0, 0, Width, Height);

            OnInitialize();
            windowsFormsWindow.m_WindowContentNeedsRedraw = true;
        }

        public override void OnInitialize()
        {
            int bitDepth = GuiHalSurface.GetBitDepthForPixelFormat(m_format);
            m_BackBuffer.Initialize(initialWidth, initialHeight, bitDepth);

            NewGraphics2D().Clear(new RGBA_Doubles(1, 1, 1, 1));

            base.OnInitialize();
        }

        public override void Run()
        {
            Show();

            while (windowsFormsWindow.Created)
            {
                Application.DoEvents();
                OnIdle();
                if (MilliSecondsToSleepEachIdle > 0)
                {
                    System.Threading.Thread.Sleep(MilliSecondsToSleepEachIdle);
                }
            }
        }
    };
}